#include "stdafx.h"
#include "cz_reg.h"
#include "cz_string.h"
#include "cz_msc.h"

#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")


// CreateKeyX ----------------------------------------------------------------------------------------------//
bool cz_reg_CreateKeyW(IN HKEY hRootKey, IN wstringc& wcsSubKey)
{
	HKEY hKey;
	if (RegCreateKeyExW(hRootKey, wcsSubKey.c_str(), 0, NULL, 0, 
		KEY_QUERY_VALUE, NULL, &hKey, NULL) != ERROR_SUCCESS) return false;
	RegCloseKey(hKey);
	return true;
}

bool cz_reg_CreateKeyA(IN HKEY hRootKey, IN stringc& strSubKey)
{
	HKEY hKey;
	if (RegCreateKeyExA(hRootKey, strSubKey.c_str(), 0, NULL, 0, 
		KEY_QUERY_VALUE, NULL, &hKey, NULL) != ERROR_SUCCESS) return false;
	RegCloseKey(hKey);
	return true;
}

// DeleteKeyX ----------------------------------------------------------------------------------------------//
bool cz_reg_DeleteKeyW(IN HKEY hRootKey, IN wstringc& wcsSubKey)
{
	LSTATUS r;
	r = SHDeleteKeyW(hRootKey, wcsSubKey.c_str());
	if ((r != ERROR_SUCCESS) && (r != ERROR_FILE_NOT_FOUND)) return false;
	return true;
}
 
bool cz_reg_DeleteKeyA(IN HKEY hRootKey, IN stringc& strSubKey)
{
	LSTATUS r;
	r = SHDeleteKeyA(hRootKey, strSubKey.c_str());
	if ((r != ERROR_SUCCESS) && (r != ERROR_FILE_NOT_FOUND)) return false;
	return true;
}

// DeleteValueX ----------------------------------------------------------------------------------------------//
bool cz_reg_DeleteValueW(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue)
{
	LSTATUS r;
	r = SHDeleteValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str());
	if ((r != ERROR_SUCCESS) && (r != ERROR_FILE_NOT_FOUND)) return false;
	return true;
}

bool cz_reg_DeleteValueA(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue)
{
	LSTATUS r;
	r = SHDeleteValueA(hRootKey, strSubKey.c_str(), strValue.c_str());
	if ((r != ERROR_SUCCESS) && (r != ERROR_FILE_NOT_FOUND)) return false;
	return true;
}

// GetStringX ----------------------------------------------------------------------------------------------//
bool cz_reg_GetStringW(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, OUT wstring& wcsData)
{
	bool r = false;
	ul type = REG_SZ, size;
	u8* pData = NULL;

	if (SHGetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), 
		&type, NULL, &size) != ERROR_SUCCESS) goto L_End;

	pData = static_cast<u8* >(malloc(size * sizeof(u8)));
	if (pData == NULL) goto L_End;

	if (SHGetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), 
		&type, pData, &size) != ERROR_SUCCESS) goto L_End;

	wcsData = reinterpret_cast<wchar* >(pData);
	r = true;

L_End:
	if (pData != NULL) free(pData);
	return r;
}

bool cz_reg_GetStringA(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, OUT string& strData)
{
	bool r = false;
	ul type = REG_SZ, size;
	u8* pData = NULL;

	if (SHGetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), 
		&type, NULL, &size) != ERROR_SUCCESS) goto L_End;

	pData = static_cast<u8* >(malloc(size * sizeof(u8)));
	if (pData == NULL) goto L_End;

	if (SHGetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), 
		&type, pData, &size) != ERROR_SUCCESS) goto L_End;

	strData = reinterpret_cast<char* >(pData);
	r = true;

L_End:
	if (pData != NULL) free(pData);
	return r;
}

// GetBinaryX ----------------------------------------------------------------------------------------------//
bool cz_reg_GetBinaryW(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, OUT vector<u8>& vctData)
{
	bool r = false;
	ul type = REG_SZ, size;
	u8* pData = NULL;

	if (SHGetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), 
		&type, NULL, &size) != ERROR_SUCCESS) goto L_End;

	pData = static_cast<u8* >(malloc(size * sizeof(u8)));
	if (pData == NULL) goto L_End;

	if (SHGetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), 
		&type, pData, &size) != ERROR_SUCCESS) goto L_End;

	vctData.assign(pData, pData + size);
	r = true;

L_End:
	if (pData != NULL) free(pData);
	return r;
}

bool cz_reg_GetBinaryA(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, OUT vector<u8>& vctData)
{
	bool r = false;
	ul type = REG_BINARY, size;
	u8* pData = NULL;

	if (SHGetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), 
		&type, NULL, &size) != ERROR_SUCCESS) goto L_End;

	pData = static_cast<u8* >(malloc(size * sizeof(u8)));
	if (pData == NULL) goto L_End;

	if (SHGetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), 
		&type, pData, &size) != ERROR_SUCCESS) goto L_End;

	vctData.assign(pData, pData + size);
	r = true;

L_End:
	if (pData != NULL) free(pData);
	return r;
}

// GetU32X -------------------------------------------------------------------------------------------------//
bool cz_reg_GetU32W(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, OUT u32& data)
{
	ul type = REG_DWORD, size = sizeof(u32);
	if (SHGetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), 
		&type, &data, &size) != ERROR_SUCCESS) return false;
	return true;
}

bool cz_reg_GetU32A(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, OUT u32& data)
{
	ul type = REG_DWORD, size = sizeof(u32);
	if (SHGetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), 
		&type, &data, &size) != ERROR_SUCCESS) return false;
	return true;
}

// GetU64X -------------------------------------------------------------------------------------------------//
bool cz_reg_GetU64W(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, OUT u64& data)
{
	ul type = REG_QWORD, size = sizeof(u64);
	if (SHGetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), 
		&type, &data, &size) != ERROR_SUCCESS) return false;
	return true;
}

bool cz_reg_GetU64A(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, OUT u64& data)
{
	ul type = REG_QWORD, size = sizeof(u64);
	if (SHGetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), 
		&type, &data, &size) != ERROR_SUCCESS) return false;
	return true;
}

// GetMultiStringX -----------------------------------------------------------------------------------------//
bool cz_reg_GetMultiStringW(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, OUT vector<wstring>& vctData)
{
	bool r = false;
	ul type = REG_MULTI_SZ, size;
	u8* pData = NULL;
	wstring wcsData;

	if (SHGetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), 
		&type, NULL, &size) != ERROR_SUCCESS) goto L_End;

	pData = static_cast<u8* >(malloc(size * sizeof(u8)));
	if (pData == NULL) goto L_End;

	if (SHGetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), 
		&type, pData, &size) != ERROR_SUCCESS) goto L_End;

	wcsData.assign(reinterpret_cast<wchar* >(pData), size / sizeof(wchar));
	vctData.clear();
	if (!cz_string_SplitW_v1(wcsData, wstring(L"\0", 1), vctData)) goto L_End;

	r = true;

L_End:
	if (pData != NULL) free(pData);
	return r;
}

bool cz_reg_GetMultiStringA(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, OUT vector<string>& vctData)
{
	bool r = false;
	ul type = REG_MULTI_SZ, size;
	u8* pData = NULL;
	string strData;

	if (SHGetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), 
		&type, NULL, &size) != ERROR_SUCCESS) goto L_End;

	pData = static_cast<u8* >(malloc(size * sizeof(u8)));
	if (pData == NULL) goto L_End;

	if (SHGetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), 
		&type, pData, &size) != ERROR_SUCCESS) goto L_End;

	strData.assign(reinterpret_cast<char* >(pData), size / sizeof(char));
	vctData.clear();
	if (!cz_string_SplitA_v1(strData, string("\0", 1), vctData)) goto L_End;

	r = true;

L_End:
	if (pData != NULL) free(pData);
	return r;
}

// GetExpandStringX ----------------------------------------------------------------------------------------//
bool cz_reg_GetExpandStringW(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, OUT wstring& wcsData)
{
	bool r = false;
	ul type = REG_SZ, size;
	u8* pData = NULL;

	if (SHGetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), 
		&type, NULL, &size) != ERROR_SUCCESS) goto L_End;

	pData = static_cast<u8* >(malloc(size * sizeof(u8)));
	if (pData == NULL) goto L_End;

	if (SHGetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), 
		&type, pData, &size) != ERROR_SUCCESS) goto L_End;

	wcsData = cz_msc_ExpandStringW(reinterpret_cast<wchar* >(pData));
	r = true;

L_End:
	if (pData != NULL) free(pData);
	return r;
}

bool cz_reg_GetExpandStringA(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, OUT string& strData)
{
	bool r = false;
	ul type = REG_SZ, size;
	u8* pData = NULL;

	if (SHGetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), 
		&type, NULL, &size) != ERROR_SUCCESS) goto L_End;

	pData = static_cast<u8* >(malloc(size * sizeof(u8)));
	if (pData == NULL) goto L_End;

	if (SHGetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), 
		&type, pData, &size) != ERROR_SUCCESS) goto L_End;

	strData = cz_msc_ExpandStringA(reinterpret_cast<char* >(pData));
	r = true;

L_End:
	if (pData != NULL) free(pData);
	return r;
}

// SetStringX ----------------------------------------------------------------------------------------------//
bool cz_reg_SetStringW(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, IN wstringc& wcsData)
{
	if (SHSetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), REG_SZ,
		wcsData.c_str(), wcsData.size() * sizeof(wchar)) != ERROR_SUCCESS) return false;
	return true;
}

bool cz_reg_SetStringA(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, IN stringc& strData)
{
	if (SHSetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), REG_SZ,
		strData.c_str(), strData.size() * sizeof(wchar)) != ERROR_SUCCESS) return false;
	return true;
}

// SetBinaryX ----------------------------------------------------------------------------------------------//
bool cz_reg_SetBinaryW(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, IN u8c* pData, IN u32 size)
{
	if (SHSetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), REG_BINARY,
		pData, size) != ERROR_SUCCESS) return false;
	return true;
}

bool cz_reg_SetBinaryA(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, IN u8c* pData, IN u32 size)
{
	if (SHSetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), REG_BINARY,
		pData, size) != ERROR_SUCCESS) return false;
	return true;
}

// Setu32X ----------------------------------------------------------------------------------------------//
bool cz_reg_SetU32W(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, IN u32 data)
{
	if (SHSetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), REG_DWORD,
		&data, sizeof(u32)) != ERROR_SUCCESS) return false;
	return true;
}

bool cz_reg_SetU32A(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, IN u32 data)
{
	if (SHSetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), REG_DWORD,
		&data, sizeof(u32)) != ERROR_SUCCESS) return false;
	return true;
}

// SetU64X ----------------------------------------------------------------------------------------------//
bool cz_reg_SetU64W(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, IN u64 data)
{
	if (SHSetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), REG_QWORD,
		&data, sizeof(u64)) != ERROR_SUCCESS) return false;
	return true;
}

bool cz_reg_SetU64A(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, IN u64 data)
{
	if (SHSetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), REG_QWORD,
		&data, sizeof(u64)) != ERROR_SUCCESS) return false;
	return true;
}

// SetMultiStringX ----------------------------------------------------------------------------------------------//
bool cz_reg_SetMultiStringW(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, OUT vector<wstring> const& vctData)
{
	wstring wcsTemp;
	wcsTemp = cz_msc_GetDoubleNullStringW(vctData);
	if (SHSetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), REG_MULTI_SZ,
		wcsTemp.c_str(), wcsTemp.size() * sizeof(wchar)) != ERROR_SUCCESS) return false;
	return true;
}

bool cz_reg_SetMultiStringA(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, OUT vector<string> const& vctData)
{
	string strTemp;
	strTemp = cz_msc_GetDoubleNullStringA(vctData);
	if (SHSetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), REG_MULTI_SZ,
		strTemp.c_str(), strTemp.size() * sizeof(char)) != ERROR_SUCCESS) return false;
	return true;
}

// SetExpandStringX ----------------------------------------------------------------------------------------------//
bool cz_reg_SetExpandStringW(IN HKEY hRootKey, IN wstringc& wcsSubKey, IN wstringc& wcsValue, IN wstringc& wcsData)
{
	if (SHSetValueW(hRootKey, wcsSubKey.c_str(), wcsValue.c_str(), REG_EXPAND_SZ,
		wcsData.c_str(), wcsData.size() * sizeof(wchar)) != ERROR_SUCCESS) return false;
	return true;
}

bool cz_reg_SetExpandStringA(IN HKEY hRootKey, IN stringc& strSubKey, IN stringc& strValue, IN stringc& strData)
{
	if (SHSetValueA(hRootKey, strSubKey.c_str(), strValue.c_str(), REG_EXPAND_SZ,
		strData.c_str(), strData.size() * sizeof(char)) != ERROR_SUCCESS) return false;
	return true;

//	bool r = false;
//	HKEY hKey;
//
//	if (RegOpenKeyExA(hRootKey, strSubKey.c_str(), 0, KEY_SET_VALUE, &hKey) != ERROR_SUCCESS) goto L_End;
//	if (RegSetValueExA(hKey, strValue.c_str(), 0, REG_EXPAND_SZ, 
//		reinterpret_cast<BYTE const* >(strData.c_str()), strData.size() * sizeof(char)) != ERROR_SUCCESS) goto L_End;
//	r = true;
//
//L_End:
//	RegCloseKey(hKey);		// would not crash with invalid handle, try to close
//	return r;
}